#include "Application.h"
#include "Renderer/Renderer.h"
#include "Core/Timestep.h"
#include "Debug/Instrumentor.h"
namespace Hazel{
    //this,std::placeholders::_1 这个是占位符，表示未来调用这个函数的第一个参数,
//#define BIND_EVENT_FN(x) std::bind(&Application::x,this,std::placeholders::_1)

    Application* Application::s_Instance = nullptr;
    Application::Application(){
        HZ_PROFILE_FUNCTION();
        m_Window = Scope<Window>(Window::Create());
        m_Window->SetEventCallback(HZ_BIND_EVENT_FN(Application::OnEvent));
//        m_Window->SetEventCallback(std::bind(&Application::OnEvent,this,std::placeholders::_1));
        s_Instance = this;
        Renderer::Init();
        m_ImGuiLayer = new ImGuiLayer();
        PushOverlay(m_ImGuiLayer);
//        Test4();

    }
    Application::~Application()
    {
        HZ_PROFILE_FUNCTION();
        Renderer::Shutdown();
    }


    void Application::OnEvent(Event& e) {
        HZ_PROFILE_FUNCTION();
        EventDispatcher dispatcher(e);
        dispatcher.Dispatch<WindowCloseEvent>(HZ_BIND_EVENT_FN(Application::OnWindowClose));
        dispatcher.Dispatch<WindowResizeEvent>(HZ_BIND_EVENT_FN(Application::OnWindowResize));
//        HZ_CORE_TRACE("{0}",e.ToString());

        // OnEvent中，透传给LayerStack，只要有一个layer消费掉了event，该事件就不在往下传递了。
        for (auto it = m_LayerStack.rbegin(); it != m_LayerStack.rend(); ++it)
        {
            (*it)->OnEvent(e);
            if (e.m_Handled)
                break;
        }
//        for (auto it = m_LayerStack.end();  it != m_LayerStack.begin();) {
//            (*--it)->OnEvent(e);
//            if (e.m_Handled) {
//                break;
//            }
//        }
    }
    void Application::Run(){
//        WindowResizeEvent e(1280, 720);
//        if (e.IsInCategory(EventCategoryApplication))
//        {
//            HZ_TRACE(e.ToString());
//        }
//        if (e.IsInCategory(EventCategoryInput))
//        {
//            HZ_TRACE(e.ToString());
//        }
        HZ_PROFILE_FUNCTION();
        while (m_Running){
            HZ_PROFILE_SCOPE("RunLoop");
//            RenderCommand::SetClearColor({0.45f, 0.55f, 0.60f, 1.00f});
//            RenderCommand::Clear();
//            m_Camera.SetPosition({0.5f, 0.5f, 0.0f});
//            m_Camera.SetRotation(45.0f);
//            Renderer::BeginScene(m_Camera);
////            m_Shader->Bind();
//            Renderer::Submit(m_Shader,m_VertexArray);
//            Renderer::EndScene();

//            m_VertexArray->Bind();
//            glDrawElements(GL_TRIANGLES, m_VertexArray->GetIndexBuffer()->GetCount(), GL_UNSIGNED_INT, nullptr);
            float time = glfwGetTime();
            Timestep timestep = time - m_LastFrameTime;
            m_LastFrameTime = time;

            if (!m_Minimized){
                {
                    HZ_PROFILE_SCOPE("LayerStack OnUpdate");

                    for (Layer* layer : m_LayerStack)
                        layer->OnUpdate(timestep);
                }

                m_ImGuiLayer->Begin();
                {
                    HZ_PROFILE_SCOPE("LayerStack OnImGuiRender");

                    for (Layer* layer : m_LayerStack)
                        layer->OnImGuiRender();
                }
                m_ImGuiLayer->End();
            }

            m_Window->OnUpdate();
        }
    }
    bool Application::OnWindowResize(Hazel::WindowResizeEvent &e) {
        if (e.GetWidth() == 0 || e.GetHeight() == 0) {
            m_Minimized = true;
            return false;
        }
        m_Minimized = false;
        uint32_t pixelWidth = e.GetWidth(), pixelHeight = e.GetHeight();
        m_Window->GetPixelSize(pixelWidth, pixelHeight);
        HZ_INFO("width = {0}, height = {1}, pixelWidth = {2}, pixelHeight = {3}", e.GetWidth(), e.GetHeight(), pixelWidth, pixelHeight);
        Renderer::OnWindowResize(pixelWidth, pixelHeight);
        return false;
    }

    bool Application::OnWindowClose(WindowCloseEvent &e) {
        HZ_PROFILE_FUNCTION();
        m_Running = false;
        return true;
    }

    void Application::PushLayer(Layer *layer) {
        m_LayerStack.PushLayer(layer);
//        layer->OnAttach();
    }

    void Application::PushOverlay(Layer *layer) {
        HZ_PROFILE_FUNCTION();
        m_LayerStack.PushOverlay(layer);
        layer->OnAttach();
    }
//    void  Application::Test3() {
//        float vertices[3 * 7] = {
//                -0.5f, -0.5, 0.0, 0.8f, 0.2f, 0.8f, 1.0f,
//                0.5f, -0.5f, 0.0f, 0.2f, 0.3f, 0.8f, 1.0f,
//                0.0f, 0.5f, 0.0f, 0.8f, 0.8f, 0.2f, 1.0f
//        };
//        // VertexBuffer::Create 通过渲染类型， 通过静态变量RendererAPI::OpenGL 创建openGlbuffer,
////        m_VertexBuffer.reset(VertexBuffer::Create(vertices,sizeof(vertices) ));
//
//        /*
//         * VertexArray = VAO 描述信息
//         *
//         *
//         * */
//        m_VertexArray.reset(VertexArray::Create());
//        std::shared_ptr<VertexBuffer> vertexBuffer(VertexBuffer::Create(vertices, sizeof(vertices)));
//        BufferLayout layout = {
//                {ShaderDataType::Float3, "a_Position"},
//                {ShaderDataType::Float4, "a_Color"},
//        };
//
//        vertexBuffer->SetLayout(layout);
//        m_VertexArray->AddVertexBuffer(vertexBuffer);
//
//        uint32_t indices[3] = {0, 1, 2};
//        std::shared_ptr<IndexBuffer> indexBuffer(IndexBuffer::Create(indices, sizeof(indices)/sizeof(uint32_t)));
//        m_VertexArray->SetIndexBuffer(indexBuffer);
////        m_IndexBuffer.reset(IndexBuffer::Create(indices,sizeof(indices) / sizeof(uint32_t)));
////        {
////            BufferLayout layout = {
////                    {ShaderDataType::Float3, "a_Position"},
////                    {ShaderDataType::Float4, "a_Color"},
////            };
////            m_VertexBuffer->SetLayout(layout);
////        }
//
////        uint32_t index = 0;
////        const auto& layout = m_VertexBuffer->GetLayout();
////        for (const auto& element : layout) {
////            glEnableVertexAttribArray(index);
////            /*
////             * 定义顶点属性为：从零开始，三组数据，浮点型，不进行归一化，每组数据为3*float(即步幅)  每个面由几个顶点
////             * 第一个参数对应shader中的第几个layout   ->layout(location = 0) out vec4 color;
////             * 第二个参数对应 一个顶点属性有几个值 3个xyz
////             * 第三个参数 每个值的类型
////             * 第四个参数 是否需要归一化  意思是数据预处理，数据转换为统一比例范围 -1 -- 1 使得不同特征或属性具有相似的数值范围。
////             * 第五个参数 跨度 一组完整数据的长度 3个坐标xyz 乘以 每个坐标的长度 (步长 * 字符类型长度)
////             * 第六个参数 偏移值吗，第一个值偏移为0
////             * */
////            HZ_TRACE(layout.GetStride());
////            glVertexAttribPointer(index,
////                                  element.GetComponentCount(),
////                                  ShaderDataTypeToOpenGLBaseType(element.Type),
////                                  element.Normallized ? GL_TRUE : GL_FALSE,
////                                  layout.GetStride(),
////                                  reinterpret_cast<void*>(element.Offset));
////            index++;
////        }
//        std::string vertexSrc = R"(
//            #version 330 core
//            layout(location = 0) in vec3 a_Position;
//            layout(location = 1) in vec4 a_Color;
//            out vec3 v_Position;
//            out vec4 v_Color; //新增
//            void main()
//            {
//                v_Position = a_Position;
//                v_Color = a_Color;
//                gl_Position = vec4(a_Position, 1.0);
//            }
//        )";
//        std::string fragmentSrc = R"(
//            #version 330 core
//            layout(location = 0) out vec4 color;
//            in vec3 v_Position;
//            in vec4 v_Color; //新增
//
//            void main()
//            {
//               // color = vec4(v_Position * 0.5 + 0.5, 1.0);
//                color = v_Color;
//            }
//        )";
////        m_Shader = std::make_shared<Shader>(vertexSrc, fragmentSrc);
////        m_Shader.reset(new Shader(vertexSrc, fragmentSrc));
//        m_Shader.reset(Hazel::Shader::Create(vertexSrc, fragmentSrc));
//    }
//    void  Application::Test4() {
//        float vertices[3 * 7] = {
//                -0.5f, -0.5, 0.0, 0.8f, 0.2f, 0.8f, 1.0f,
//                0.5f, -0.5f, 0.0f, 0.2f, 0.3f, 0.8f, 1.0f,
//                0.0f, 0.5f, 0.0f, 0.8f, 0.8f, 0.2f, 1.0f
//        };
//        m_VertexArray.reset(VertexArray::Create());
//        std::shared_ptr<VertexBuffer> vertexBuffer(VertexBuffer::Create(vertices, sizeof(vertices)));
//        BufferLayout layout = {
//                {ShaderDataType::Float3, "a_Position"},
//                {ShaderDataType::Float4, "a_Color"},
//        };
//
//        vertexBuffer->SetLayout(layout);
//        m_VertexArray->AddVertexBuffer(vertexBuffer);
//
//        uint32_t indices[3] = {0, 1, 2};
//        std::shared_ptr<IndexBuffer> indexBuffer(IndexBuffer::Create(indices, sizeof(indices)/sizeof(uint32_t)));
//        m_VertexArray->SetIndexBuffer(indexBuffer);
//
//        std::string vertexSrc = R"(
//            #version 330 core
//            layout(location = 0) in vec3 a_Position;
//            layout(location = 1) in vec4 a_Color;
//            uniform mat4 u_ViewProjection;
//            out vec3 v_Position;
//            out vec4 v_Color; //新增
//            void main()
//            {
//                v_Position = a_Position;
//                v_Color = a_Color;
//                gl_Position = u_ViewProjection * vec4(a_Position, 1.0);
//            }
//        )";
//        std::string fragmentSrc = R"(
//            #version 330 core
//            layout(location = 0) out vec4 color;
//            in vec3 v_Position;
//            in vec4 v_Color; //新增
//
//            void main()
//            {
//               // color = vec4(v_Position * 0.5 + 0.5, 1.0);
//                color = v_Color;
//            }
//        )";
////        m_Shader = std::make_shared<Shader>(vertexSrc, fragmentSrc);
//        m_Shader.reset(Hazel::Shader::Create(vertexSrc, fragmentSrc));
//    }
}

//void Hazel::Application::CreateTest() {
//// 生成顶点数组
////    glGenVertexArrays(1, &m_VertexArray);
////    // 绑定顶点数组
////    glBindVertexArray(m_VertexArray);
////
////    // 生成顶点缓冲
////    glGenBuffers(1, &m_VertexBuffer);
////    // 绑定数组缓冲
////    glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
////
////    float vertices[4*6]{
////        -1,1,0,
////        1,1,0,
////        1,-1,0,
////        -1,-1,0
////    };
////    // 填充数组数据。三角形数据绑定到GPU上
////    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//////        glBufferData(GL_ARRAY_BUFFER, sizeof(verticesV), verticesV, GL_STATIC_DRAW);
////
////    // enable第一个顶点数组，对应shader中的顶点数据
////    glEnableVertexAttribArray(0);
////    // 定义顶点属性为：从零开始，三组数据，浮点型，不进行归一化，每组数据为3*float(即步幅)  每个面由几个顶点
////    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), nullptr);
////
////    // 生成索引缓冲，本质都是缓冲和顶点缓冲没区别，存不同的数据而已
////    glGenBuffers(1, &m_IndexBuffer);
////    // 绑定到索引缓冲
////    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IndexBuffer);
////    // 定义索引 =线
////    unsigned int indices[6] = {0, 2, 1,0,4,2};
////    //将indices填充索引缓冲数据(发送到GPU)
////    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//}
//
//void Hazel::Application::Test2() {
////    float vertices[4*6]{
////            -1,1,0,
////            1,1,0,
////            1,-1,0,
////            -1,-1,0
////    };
////    // VertexBuffer::Create 通过渲染类型， 通过静态变量RendererAPI::OpenGL 创建openGlbuffer,
////    m_VertexBuffer.reset(VertexBuffer::Create(vertices,sizeof(vertices) ));
////    // enable第一个顶点数组，对应shader中的顶点数据
////    glEnableVertexAttribArray(0);
////    /*
////     * 定义顶点属性为：从零开始，三组数据，浮点型，不进行归一化，每组数据为3*float(即步幅)  每个面由几个顶点
////     * 第一个参数对应shader中的第几个layout   ->layout(location = 0) out vec4 color;
////     * 第二个参数对应 一个顶点属性有几个值 3个xyz
////     * 第三个参数 每个值的类型
////     * 第四个参数 是否需要归一化  意思是数据预处理，数据转换为统一比例范围 -1 -- 1 使得不同特征或属性具有相似的数值范围。
////     * 第五个参数 跨度 一组完整数据的长度 3个坐标xyz 乘以 每个坐标的长度
////     * 第六个参数 偏移值吗，第一个值偏移为0
////     * */
////    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), nullptr);
////    unsigned int indices[6] = {0, 2, 1,0,4,2};
////    m_IndexBuffer.reset(IndexBuffer::Create(indices,sizeof(indices) / sizeof(uint32_t)));
//}
